
#include <stdio.h>
#include <stdbool.h>
#include <aos/aos.h>
#include <yoc/yoc.h>
#include <sys_freq.h>

#include "soc.h"
#include "pin_name.h"
#include "pin.h"
#include "board_sensor.h"
// #include "board.h"
#include "aogpio.h"

#define reg_wr(reg_addr) *((volatile uint32_t *)(reg_addr))

static void camera_io_out32(uint32_t addr, uint32_t value)			//write
{
	volatile uint32_t *ptr = (volatile uint32_t *)(addr);
	//printf("write: addr=0x%x, data=0x%x\n", addr, value);
	*ptr = value;
}

static uint32_t camera_io_in32(uint32_t addr)						//read
{
	volatile uint32_t *ptr = (volatile uint32_t *)(addr);
	//printf("read:  addr=0x%x, data=0x%x\n", ptr, *ptr);
	
	return *ptr;
}

static void camera_io_rstn_init(uint8_t index)
{
	uint32_t reg_val;

	reg_val = camera_io_in32(CSKY_AOGPIO_BASE + 0x04);
	reg_val |= (0x1 << index);
	
	camera_io_out32(CSKY_AOGPIO_BASE + 0x04, reg_val);
}

void camera_io_rstn_set(uint8_t index, bool level)
{
	uint32_t reg_val;

	reg_val = camera_io_in32(CSKY_AOGPIO_BASE + 0x00); 
	if (level)
		reg_val |= (0x1 << index);
	else
		reg_val &= ~(0x1 << index);

	camera_io_out32(CSKY_AOGPIO_BASE + 0x00, reg_val);
}

void sensorHwReset(int sensor_idx){
    camera_io_rstn_init(sensor_idx);
    camera_io_rstn_set(sensor_idx, true);    aos_msleep(1);
    camera_io_rstn_set(sensor_idx, false);   aos_msleep(1);
    camera_io_rstn_set(sensor_idx, true);    aos_msleep(1);
}

#define MCLK_DIV_24M_SHIFT		4
#define MCLK_DIV_CPU_PLL_SHIFT	8
#define MCLK_SRC_SEL_CPU_PLL	1
#define MCLK_SRC_SEL_24M		0
#define MCLK_MAX_24M_DIV		4
#define MCLK_MAX_CPU_PLL_DIV 	8

static CLKGEN_REG_S clkgen_reg;

static inline uint32_t inl(uint32_t addr)
{
    return *(volatile uint32_t *)addr;
}

static inline void outl(uint32_t val, uint32_t addr)
{
    *(volatile uint32_t *)addr = val;
}

int32_t drv_set_mclk_board(mclk_cfg_t *cfg)
{
	uint8_t div_shift;
	uint8_t src_clk;


	if (cfg == NULL) {
		printf("%s %d:input para err\r\n", __func__, __LINE__);
		return -1;		
	}
	
	if (cfg->src_clk == MCLK_EXT_24M) {
		if (cfg->div_ratio >= MCLK_MAX_24M_DIV) {
			printf("%s %d:unknow mclk div_ratio %d\r\n", __func__, __LINE__,
				cfg->div_ratio);
			return -1;				
		}
		div_shift = MCLK_DIV_24M_SHIFT;
		src_clk = MCLK_SRC_SEL_24M;
	} else if (cfg->src_clk == MCLK_CPU_PLL) {
		if (cfg->div_ratio >= MCLK_MAX_CPU_PLL_DIV) {
			printf("%s %d:unknow mclk div_ratio %d\r\n", __func__, __LINE__,
				cfg->div_ratio);
			return -1;				
		}
		div_shift = MCLK_DIV_CPU_PLL_SHIFT;
		src_clk = MCLK_SRC_SEL_CPU_PLL;
	} else {
		printf("%s %d:unknow mclk src clk %d\r\n", __func__, __LINE__,
			cfg->src_clk);
		return -1;		
	}

	switch (cfg->index) 
	{
	case 0:
		clkgen_reg.chip_oclk_cfg0.u32 = inl(CSKY_CLKGEN_BASE + CHIP_OCLK_CFG0);
		clkgen_reg.chip_oclk_cfg0.chip_oclk0_div_sync = 0;
		clkgen_reg.chip_oclk_cfg0.chip_oclk0_en = 0;
		clkgen_reg.chip_oclk_cfg0.chip_oclk0_div1 = 0;
		clkgen_reg.chip_oclk_cfg0.chip_oclk0_div0 = 0;
		outl(clkgen_reg.chip_oclk_cfg0.u32, CSKY_CLKGEN_BASE + CHIP_OCLK_CFG0);
		clkgen_reg.chip_oclk_cfg0.chip_oclk0_src_sel = src_clk;
		clkgen_reg.chip_oclk_cfg0.u32 |=  (cfg->div_ratio << div_shift);
		clkgen_reg.chip_oclk_cfg0.chip_oclk0_div_sync = 1;
		clkgen_reg.chip_oclk_cfg0.chip_oclk0_en = 1;		
		outl(clkgen_reg.chip_oclk_cfg0.u32, CSKY_CLKGEN_BASE + CHIP_OCLK_CFG0);
		break;
	case 1:
		clkgen_reg.chip_oclk_cfg0.u32 = inl(CSKY_CLKGEN_BASE + CHIP_OCLK_CFG0);
		clkgen_reg.chip_oclk_cfg0.chip_oclk1_div_sync = 0;
		clkgen_reg.chip_oclk_cfg0.chip_oclk1_en = 0;
		clkgen_reg.chip_oclk_cfg0.chip_oclk1_div1 = 0;
		clkgen_reg.chip_oclk_cfg0.chip_oclk1_div0 = 0;
		outl(clkgen_reg.chip_oclk_cfg0.u32, CSKY_CLKGEN_BASE + CHIP_OCLK_CFG0);
		clkgen_reg.chip_oclk_cfg0.chip_oclk1_src_sel = src_clk;
		div_shift += 16;
		clkgen_reg.chip_oclk_cfg0.u32 |=  (cfg->div_ratio << div_shift);
		clkgen_reg.chip_oclk_cfg0.chip_oclk1_div_sync = 1;
		clkgen_reg.chip_oclk_cfg0.chip_oclk1_en = 1;		
		outl(clkgen_reg.chip_oclk_cfg0.u32, CSKY_CLKGEN_BASE + CHIP_OCLK_CFG0);
		break;		
	case 2:
		clkgen_reg.chip_oclk_cfg1.u32 = inl(CSKY_CLKGEN_BASE + CHIP_OCLK_CFG1);
		clkgen_reg.chip_oclk_cfg1.chip_oclk2_div_sync = 0;
		clkgen_reg.chip_oclk_cfg1.chip_oclk2_en = 0;
		clkgen_reg.chip_oclk_cfg1.chip_oclk2_div1 = 0;
		clkgen_reg.chip_oclk_cfg1.chip_oclk2_div0 = 0;
		outl(clkgen_reg.chip_oclk_cfg1.u32, CSKY_CLKGEN_BASE + CHIP_OCLK_CFG1);
		clkgen_reg.chip_oclk_cfg1.chip_oclk2_src_sel = src_clk;
		clkgen_reg.chip_oclk_cfg1.u32 |=  (cfg->div_ratio << div_shift);
		clkgen_reg.chip_oclk_cfg1.chip_oclk2_div_sync = 1;
		clkgen_reg.chip_oclk_cfg1.chip_oclk2_en = 1;		
		outl(clkgen_reg.chip_oclk_cfg1.u32, CSKY_CLKGEN_BASE + CHIP_OCLK_CFG1);
		break;
	case 3:
		clkgen_reg.chip_oclk_cfg1.u32 = inl(CSKY_CLKGEN_BASE + CHIP_OCLK_CFG1);
		clkgen_reg.chip_oclk_cfg1.chip_oclk3_div_sync = 0;
		clkgen_reg.chip_oclk_cfg1.chip_oclk3_en = 0;
		clkgen_reg.chip_oclk_cfg1.chip_oclk3_div1 = 0;
		clkgen_reg.chip_oclk_cfg1.chip_oclk3_div0 = 0;
		outl(clkgen_reg.chip_oclk_cfg1.u32, CSKY_CLKGEN_BASE + CHIP_OCLK_CFG1);
		clkgen_reg.chip_oclk_cfg1.chip_oclk3_src_sel = src_clk;
		div_shift += 16;
		clkgen_reg.chip_oclk_cfg1.u32 |=  (cfg->div_ratio << div_shift);
		clkgen_reg.chip_oclk_cfg1.chip_oclk3_div_sync = 1;
		clkgen_reg.chip_oclk_cfg1.chip_oclk3_en = 1;		
		outl(clkgen_reg.chip_oclk_cfg1.u32, CSKY_CLKGEN_BASE + CHIP_OCLK_CFG1);
		break;		
	default:
		printf("%s %d:unknow mclk index %d\r\n", __func__, __LINE__, cfg->index);
		return -1;
	}

	return 0;
}

void sensorMclkConfig(int mclk_idx){
    int ret = 0;
    mclk_cfg_t mclk_cfg;

    mclk_cfg.index = mclk_idx;
    mclk_cfg.src_clk = MCLK_EXT_24M;
    mclk_cfg.div_ratio = 2;
    ret = drv_set_mclk_board(&mclk_cfg);
    if (ret) {
        printf("%s set mclk failed.\n",__func__);

    }
}


#define PMU_LDO_GPIO_EN1 4
#define PMU_LDO_GPIO_EN2 9

extern void vo_init();
extern int ifv_Initial_visbuffer();
void hw_init()
{
    int32_t ret;
	ifv_Initial_visbuffer();
    aogpio_set_direction(PMU_LDO_GPIO_EN1, AO_GPIO_OUTPUT);
    aogpio_write(PMU_LDO_GPIO_EN1, 0);
    aos_msleep(1);
    aogpio_write(PMU_LDO_GPIO_EN1, 1);
    aos_msleep(1);

    aogpio_set_direction(PMU_LDO_GPIO_EN2, AO_GPIO_OUTPUT);
    aogpio_write(PMU_LDO_GPIO_EN2, 0);
    aos_msleep(1);
    aogpio_write(PMU_LDO_GPIO_EN2, 1);
    aos_msleep(1);

    sensorHwReset(OV2732_RGB_RSTN_INDEX);
    sensorHwReset(OV2732_IR_RSTN_INDEX);
    sensorHwReset(OV27332_IR_PWRDN);
    sensorMclkConfig(OV2732_MCLK_INDEX-1);

    ret = camera_ov2732_rgb_init();
    if (ret)
    {
        printf("Failed to initialize camera ov2732\r\n");
    }
    
    ret = camera_ov2732_ir_init();
    if (ret)
    {
        printf("Failed to initialize camera ov2732\r\n");
    }
    
    vo_init();
}

void board_init(void)
{
    reg_wr(0XFFF20000 + 0x78) = 0x8408800;
    reg_wr(0XFFF20000 + 0x78) = 0x8409800;

    reg_wr(CSKY_AOGPIO_BASE + 0x04) |= (0x1 << 5) | (0x1 << 7)|(0x1 << 11) |(0x1 << 4) | (0x1 << 9);

    reg_wr(CSKY_AOGPIO_BASE + 0x00) |= (0x0 << 7) | (0x0 << 11);
    reg_wr(CSKY_AOGPIO_BASE + 0x00) |= (0x1 << 5);				 //IR_PWRDN
    reg_wr(CSKY_AOGPIO_BASE + 0x00) |= (0x1 << 4) |(0x1 << 9) ;	 //PMU_LDO_EN1 PMU_LDO_EN2
    reg_wr(CSKY_AOGPIO_BASE + 0x00) |= (0x1 << 7) | (0x1 << 11);	//IR rest/RGB reset

    /* config sd card sdio 1 clk source */
    drv_sdio_config_freq(1);
}
